package com.glory.brepda.base;

import android.Manifest;
import android.app.Application;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import pub.devrel.easypermissions.EasyPermissions;


import com.glory.brepda.activity.LoginActivity;
import com.glory.brepda.utils.ShellUtils;
import com.google.gson.reflect.TypeToken;
import com.lzy.okgo.model.Response;
import com.pda.platform.ui.ui_pdaplatform.base.FreeUI_InitUtils;
import com.pda.platform.ui.ui_pdaplatform.callback.FreeUI_EntityCallBack;
import com.pda.platform.ui.ui_pdaplatform.entity.FreeUI_VersionEntity;
import com.pda.platform.ui.ui_pdaplatform.utils_public.FreeApi_ActivityManager;
import com.pda.platform.ui.ui_pdaplatform.utils_public.FreeApi_DateUtils;
import com.pda.platform.ui.ui_pdaplatform.utils_public.FreeApi_NetUtils;
import com.pda.platform.ui.ui_pdaplatform.utils_public.FreeApi_StaticMembers;
import com.pda.platform.ui.ui_pdaplatform.utils_public.FreeApi_ToastUtils;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

 /**
 * FileName: MyApp
 * Author: XJH
 * Date: 2020/5/12 11:30
 * Description:
 * History:
 */
public class MyApp extends Application {

    public static Context app;
    private static MyApp instance;
    private long TINE_TASK_AN_HOUR = 60 * 60 * 1000L;
    private int code;
    private static final String TAG = "GLORY_TIMER_TASK";

     private final Timer timer = new Timer();
     private TimerTask task;
     Handler handler = new Handler(){
         @Override
         public void handleMessage(@NonNull Message msg) {
             switch (msg.what){
                 case 0:
                     Toast.makeText(MyApp.this, "时间同步成功", Toast.LENGTH_SHORT).show();
                     break;
                 case 1:
//                     Toast.makeText(MyApp.this, "时间同步失败", Toast.LENGTH_SHORT).show();
                     break;
                 case 5486:
                     Log.e(TAG, FreeApi_DateUtils.getNowStringDate("HH:mm:ss") +" 收到定时任务" );
                     //比对版本
                     detectionUpdate();
                     break;
             }
//             if (msg.what == 5486){
//                 Log.e(TAG, FreeApi_DateUtils.getNowStringDate("HH:mm:ss") +" 收到定时任务" );
//                 //比对版本
//                 detectionUpdate();
//             }
             super.handleMessage(msg);
         }
     };

    public static MyApp getInstance() {
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        app = getApplicationContext();
        FreeUI_InitUtils.init(getApplicationContext(), this, true,40 * 1000L,0);
        FreeUI_InitUtils.setTheme(FreeApi_StaticMembers.THEME_GLORY);
        Log.e(TAG, FreeApi_DateUtils.getNowStringDate("HH:mm:ss") + "APP启动了");
//        get_root();
        startCalibrateTime();
        new Handler().postDelayed(() -> showTimer(),TINE_TASK_AN_HOUR);
    }

     public void get_root(){

         if (is_root()){
             Toast.makeText(this, "已经具有ROOT权限!", Toast.LENGTH_LONG).show();
         }

         else{
             try{
                 Runtime.getRuntime().exec("su");
             }
             catch (Exception e){
                 Log.i("ExceptionAAA",e.getMessage());
                 Toast.makeText(this, "获取ROOT权限时出错!", Toast.LENGTH_LONG).show();
             }
         }
     }

     public static boolean is_root() {
         boolean res = false;
         try {
             if ((!new File("/system/bin/su").exists()) &&
                     (!new File("/system/xbin/su").exists())) {
                         res = false;
             } else {
                 res = true;
             }

         } catch (Exception e) {
             res = false;
         }
         return res;
     }

     private void showTimer() {
         Log.e(TAG,  FreeApi_DateUtils.getNowStringDate("HH:mm:ss") + "开始执行定时任务");
         task = new TimerTask() {
             @Override
             public void run() {
                 Message message = new Message();
                 message.what = 5486;
                 Log.e(TAG, FreeApi_DateUtils.getNowStringDate("HH:mm:ss") +" 发送定时任务" );
                 handler.sendMessage(message);
             }
         };
         timer.schedule(task,new Date(),TINE_TASK_AN_HOUR);
     }

     @Override
     public void onTerminate() {
         //关闭定时任务
         task.cancel();
         Log.e(TAG, "onTerminate: 关闭定时任务" );
         super.onTerminate();
     }

     private void detectionUpdate()    {
         PackageManager manager = getPackageManager();
         PackageInfo info = null;
         try {
             info = manager.getPackageInfo(getPackageName(), 0);
         } catch (PackageManager.NameNotFoundException e) {
             e.printStackTrace();
         }
         String version = info.versionName;
         FreeUI_EntityCallBack<FreeUI_VersionEntity> callBack = new FreeUI_EntityCallBack<FreeUI_VersionEntity>
                 (new TypeToken<FreeUI_VersionEntity>() {
                 }.getType()) {

             @Override
             public void onSuccess(Response<FreeUI_VersionEntity> response) {
                 FreeUI_VersionEntity entity = response.body();
                 entity.setCurrentVersion(version);
                 code = compareVersion(version,entity.getVersion());
                 if(code == -1) {
                     Toast.makeText(MyApp.this, "发现最新版本!正在前往更新", Toast.LENGTH_SHORT).show();
                     timer.cancel();
//
//                     Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
//                     PendingIntent restartIntent = PendingIntent.getActivity(getApplicationContext(), 200, intent, PendingIntent.FLAG_ONE_SHOT);
//                     AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
//                     mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000L, restartIntent);

//                     FreeApi_ActivityManager.getActivityManager().AppExit(getApplicationContext());
                     FreeApi_ActivityManager.getActivityManager().finishAllActivity();
                     Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
                     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                     intent.setAction(intent.FLAG_ACTIVITY_NEW_TASK);
                     startActivity(intent);

                 }

             }

             @Override
             public void onError
                     (Response<FreeUI_VersionEntity> response) {
                 super.onError(response);
             }
         };
         Map<String, String> map = new HashMap<>();
         FreeApi_NetUtils.requestGetNet(Constant.FILE_URL, this, map, callBack);
     }

     public static int compareVersion(String version1, String version2) {
         if (version1.equals(version2)) {
             return 0;
         } else {
             String[] version1Array = version1.split("\\.");
             String[] version2Array = version2.split("\\.");
             Log.d("HomePageActivity", "version1Array==" + version1Array.length);
             Log.d("HomePageActivity", "version2Array==" + version2Array.length);
             int index = 0;
             int minLen = Math.min(version1Array.length, version2Array.length);
             int diff = 0;
             Log.d("HomePageActivity", "verTag2=2222=" + version1Array[index]);

             while(index < minLen && (diff = Integer.parseInt(version1Array[index]) - Integer.parseInt(version2Array[index])) == 0) {
                 ++index;
             }

             if (diff == 0) {
                 int i;
                 for(i = index; i < version1Array.length; ++i) {
                     if (Integer.parseInt(version1Array[i]) > 0) {
                         return 1;
                     }
                 }

                 for(i = index; i < version2Array.length; ++i) {
                     if (Integer.parseInt(version2Array[i]) > 0) {
                         return -1;
                     }
                 }

                 return 0;
             } else {
                 return diff > 0 ? 1 : -1;
             }
         }
     }

     private final int NTP_TIME_OUT_MILLISECOND = 30000;

     private boolean isStopCalibrate = false;
     /**
      * ntp服务器地址集
      */
     private String[] ntpServerHost = new String[]{
             "dns1.synet.edu.cn",
             "news.neu.edu.cn",
             "dns.sjtu.edu.cn",
             "dns2.synet.edu.cn",
             "ntp.glnet.edu.cn",
             "ntp-sz.chl.la",
             "ntp.gwadar.cn",
             "cn.pool.ntp.org"
     };
     /**
      * 开始校准时间
      */
     public void startCalibrateTime() {
         new Thread() {
             @Override
             public void run() {
                 while (!isStopCalibrate) {
                     for (int i = 0; i < ntpServerHost.length; i++) {
                         long time = getTimeFromNtpServer(ntpServerHost[i]);

                         if (time != -1) {
                             int tryCount = 3;
                             while (tryCount > 0) {
                                 tryCount--;
                                 boolean isSetTimeSuccessful = setCurrentTimeMillis(time);
//                                 if (isSetTimeSuccessful) {
                                     tryCount = 0;
                                     isStopCalibrate = true;
//                                     Message message = new Message();
//                                     message.what = 0;
//                                     handler.sendMessage(message);
//                                  } else {
//                                     Message message = new Message();
//                                     message.what = 1;
//                                     handler.sendMessage(message);
//                                 }
                             }
                             break;
                         }
                     }
                 }
             }
         }.start();
     }

     /**
      * 停止校准时间
      */
     public void stopCalibrateTime() {
         isStopCalibrate = true;
     }

     /**
      * 从ntp服务器中获取时间
      *
      * @param ntpHost ntp服务器域名地址
      * @return 如果失败返回-1，否则返回当前的毫秒数
      */
     private long getTimeFromNtpServer(String ntpHost) {
         SntpClient client = new SntpClient();
         boolean isSuccessful = client.requestTime(ntpHost, NTP_TIME_OUT_MILLISECOND);
         if (isSuccessful) {
             return client.getNtpTime();
         }
         return -1;
     }


     /**
      * 设置当前的系统时间
      *
      * @param time
      * @return true表示设置成功, false表示设置失败
      */
     public boolean setCurrentTimeMillis(long time) {
         try {
             if (ShellUtils.checkRootPermission()) {
                 TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
                 Date current = new Date(time);
                 SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd.HHmmss");
                 String datetime = df.format(current);
                 Process process = Runtime.getRuntime().exec("su");
                 DataOutputStream os = new DataOutputStream(process.getOutputStream());
                 //os.writeBytes("setprop persist.sys.timezone GMT\n");
                 os.writeBytes("/system/bin/date -s " + "2022329.101111" + "\n");
                 os.writeBytes("clock -w\n");
                 os.writeBytes("exit\n");
                 os.flush();
                 return true;
             } else {
                 return false;
             }
         } catch (Exception e) {
             return false;
         }
     }

     public static class SntpClient {
         private static final String TAG = "SntpClient";

         private static final int REFERENCE_TIME_OFFSET = 16;
         private static final int ORIGINATE_TIME_OFFSET = 24;
         private static final int RECEIVE_TIME_OFFSET = 32;
         private static final int TRANSMIT_TIME_OFFSET = 40;
         private static final int NTP_PACKET_SIZE = 48;

         private static final int NTP_PORT = 123;
         private static final int NTP_MODE_CLIENT = 3;
         private static final int NTP_VERSION = 3;

         // Number of seconds between Jan 1, 1900 and Jan 1, 1970
         // 70 years plus 17 leap days
         private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

         // system time computed from NTP server response
         private long mNtpTime;

         // value of SystemClock.elapsedRealtime() corresponding to mNtpTime
         private long mNtpTimeReference;

         // round trip time in milliseconds
         private long mRoundTripTime;

         /**
          * Sends an SNTP request to the given host and processes the response.
          *
          * @param host    host name of the server.
          * @param timeout network timeout in milliseconds.
          * @return true if the transaction was successful.
          */
         public boolean requestTime(String host, int timeout) {
             DatagramSocket socket = null;
             try {
                 socket = new DatagramSocket();
                 socket.setSoTimeout(timeout);
                 InetAddress address = InetAddress.getByName(host);
                 byte[] buffer = new byte[NTP_PACKET_SIZE];
                 DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);

                 // set mode = 3 (client) and version = 3
                 // mode is in low 3 bits of first byte
                 // version is in bits 3-5 of first byte
                 buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

                 // get current time and write it to the request packet
                 long requestTime = System.currentTimeMillis();
                 long requestTicks = SystemClock.elapsedRealtime();
                 writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);

                 socket.send(request);

                 // read the response
                 DatagramPacket response = new DatagramPacket(buffer, buffer.length);
                 socket.receive(response);
                 long responseTicks = SystemClock.elapsedRealtime();
                 long responseTime = requestTime + (responseTicks - requestTicks);

                 // extract the results
                 long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
                 long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
                 long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
                 long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
                 // receiveTime = originateTime + transit + skew
                 // responseTime = transmitTime + transit - skew
                 // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
                 //             = ((originateTime + transit + skew - originateTime) +
                 //                (transmitTime - (transmitTime + transit - skew)))/2
                 //             = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
                 //             = (transit + skew - transit + skew)/2
                 //             = (2 * skew)/2 = skew
                 long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;
                 // if (false) Log.d(TAG, "round trip: " + roundTripTime + " ms");
                 // if (false) Log.d(TAG, "clock offset: " + clockOffset + " ms");

                 // save our results - use the times on this side of the network latency
                 // (response rather than request time)
                 mNtpTime = responseTime + clockOffset;
                 mNtpTimeReference = responseTicks;
                 mRoundTripTime = roundTripTime;
             } catch (Exception e) {
                 if (false) Log.d(TAG, "request time failed: " + e);
                 return false;
             } finally {
                 if (socket != null) {
                     socket.close();
                 }
             }

             return true;
         }

         /**
          * Returns the time computed from the NTP transaction.
          *
          * @return time value computed from NTP server response.
          */
         public long getNtpTime() {
             return mNtpTime;
         }

         /**
          * Returns the reference clock value (value of SystemClock.elapsedRealtime())
          * corresponding to the NTP time.
          *
          * @return reference clock corresponding to the NTP time.
          */
         public long getNtpTimeReference() {
             return mNtpTimeReference;
         }

         /**
          * Returns the round trip time of the NTP transaction
          *
          * @return round trip time in milliseconds.
          */
         public long getRoundTripTime() {
             return mRoundTripTime;
         }

         /**
          * Reads an unsigned 32 bit big endian number from the given offset in the buffer.
          */
         private long read32(byte[] buffer, int offset) {
             byte b0 = buffer[offset];
             byte b1 = buffer[offset + 1];
             byte b2 = buffer[offset + 2];
             byte b3 = buffer[offset + 3];

             // convert signed bytes to unsigned values
             int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
             int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
             int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
             int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

             return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3;
         }

         /**
          * Reads the NTP time stamp at the given offset in the buffer and returns
          * it as a system time (milliseconds since January 1, 1970).
          */
         private long readTimeStamp(byte[] buffer, int offset) {
             long seconds = read32(buffer, offset);
             long fraction = read32(buffer, offset + 4);
             return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
         }

         /**
          * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp
          * at the given offset in the buffer.
          */
         private void writeTimeStamp(byte[] buffer, int offset, long time) {
             long seconds = time / 1000L;
             long milliseconds = time - seconds * 1000L;
             seconds += OFFSET_1900_TO_1970;

             // write seconds in big endian format
             buffer[offset++] = (byte) (seconds >> 24);
             buffer[offset++] = (byte) (seconds >> 16);
             buffer[offset++] = (byte) (seconds >> 8);
             buffer[offset++] = (byte) (seconds >> 0);

             long fraction = milliseconds * 0x100000000L / 1000L;
             // write fraction in big endian format
             buffer[offset++] = (byte) (fraction >> 24);
             buffer[offset++] = (byte) (fraction >> 16);
             buffer[offset++] = (byte) (fraction >> 8);
             // low order bits should be random data
             buffer[offset++] = (byte) (Math.random() * 255.0);
         }
     }

}
